package org.example.jnautil.key;

import lombok.Getter;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * windows虚拟按键码全集：
 * https://learn.microsoft.com/zh-cn/windows/win32/inputdev/virtual-key-codes?redirectedfrom=MSDN
 * <p>
 * javafx.scene.input.KeyCode 包含可读的名称，但按键码不一定准确
 * com.sun.jna.platform.win32.Win32VK 包含准确的按键码，但不易读
 * com.sun.glass.events.KeyEvent  这个待测试
 */
@Getter
public enum KeyCodeEnum {

    // 有很多错误和冗余，用到的时候再改吧

    VK_UNDEFINED(0, "Undefined"),
    VK_CANCEL(3, "Cancel"),
    VK_BACK(8, "Backspace"),
    VK_TAB(9, "Tab"),
    VK_RESERVED_0A(10, "Enter"),
    VK_CLEAR(12, "Clear"),
    VK_RETURN(13, "Enter"),
    VK_SHIFT(16, "Shift"),
    VK_MENU(18, "Alt"),
    VK_PAUSE(19, "Pause"),
    VK_CAPITAL(20, "Caps Lock"),
    VK_HANGUL(21, "Kana"),
    VK_FINAL(24, "Final"),
    VK_KANJI(25, "Kanji"),
    VK_ESCAPE(27, "Esc"),
    VK_CONVERT(28, "Convert"),
    VK_NONCONVERT(29, "Nonconvert"),
    VK_ACCEPT(30, "Accept"),
    VK_MODECHANGE(31, "Mode Change"),
    VK_SPACE(32, "Space"),
    VK_PRIOR(33, "Page Up"),
    VK_NEXT(34, "Page Down"),
    VK_END(35, "End"),
    VK_HOME(36, "Home"),
    VK_LEFT(37, "Left"),
    VK_UP(38, "Up"),
    VK_RIGHT(39, "Right"),
    VK_DOWN(40, "Down"),
    VK_SNAPSHOT(44, "Print Screen"),
    VK_INSERT(45, "Insert"),
    VK_DELETE(46, "Delete"),
    VK_HELP(47, "Slash"),
    VK_0(48, "0"),
    VK_1(49, "1"),
    VK_2(50, "2"),
    VK_3(51, "3"),
    VK_4(52, "4"),
    VK_5(53, "5"),
    VK_6(54, "6"),
    VK_7(55, "7"),
    VK_8(56, "8"),
    VK_9(57, "9"),
    VK_UNASSIGNED_3B(59, "Semicolon"),
    VK_UNASSIGNED_3D(61, "Equals"),
    VK_A(65, "A"),
    VK_B(66, "B"),
    VK_C(67, "C"),
    VK_D(68, "D"),
    VK_E(69, "E"),
    VK_F(70, "F"),
    VK_G(71, "G"),
    VK_H(72, "H"),
    VK_I(73, "I"),
    VK_J(74, "J"),
    VK_K(75, "K"),
    VK_L(76, "L"),
    VK_M(77, "M"),
    VK_N(78, "N"),
    VK_O(79, "O"),
    VK_P(80, "P"),
    VK_Q(81, "Q"),
    VK_R(82, "R"),
    VK_S(83, "S"),
    VK_T(84, "T"),
    VK_U(85, "U"),
    VK_V(86, "V"),
    VK_W(87, "W"),
    VK_X(88, "X"),
    VK_Y(89, "Y"),
    VK_Z(90, "Z"),
    VK_LWIN(91, "Windows"),
    VK_RWIN(92, "Back Slash"),
    VK_APPS(93, "VK_APPS"),
    VK_NUMPAD0(96, "Numpad 0"),
    VK_NUMPAD1(97, "Numpad 1"),
    VK_NUMPAD2(98, "Numpad 2"),
    VK_NUMPAD3(99, "Numpad 3"),
    VK_NUMPAD4(100, "Numpad 4"),
    VK_NUMPAD5(101, "Numpad 5"),
    VK_NUMPAD6(102, "Numpad 6"),
    VK_NUMPAD7(103, "Numpad 7"),
    VK_NUMPAD8(104, "Numpad 8"),
    VK_NUMPAD9(105, "Numpad 9"),
    VK_MULTIPLY(106, "Multiply"),
    VK_ADD(107, "Add"),
    VK_SEPARATOR(108, "Separator"),
    VK_SUBTRACT(109, "Subtract"),
    VK_DECIMAL(110, "Decimal"),
    VK_DIVIDE(111, "Divide"),
    VK_F1(112, "F1"),
    VK_F2(113, "F2"),
    VK_F3(114, "F3"),
    VK_F4(115, "F4"),
    VK_F5(116, "F5"),
    VK_F6(117, "F6"),
    VK_F7(118, "F7"),
    VK_F8(119, "F8"),
    VK_F9(120, "F9"),
    VK_F10(121, "F10"),
    VK_F11(122, "F11"),
    VK_F12(123, "F12"),
    VK_F16(127, "Delete"),
    VK_F17(128, "Dead Grave"),
    VK_F18(129, "Dead Acute"),
    VK_F19(130, "Dead Circumflex"),
    VK_F20(131, "Dead Tilde"),
    VK_F21(132, "Dead Macron"),
    VK_F22(133, "Dead Breve"),
    VK_F23(134, "Dead Abovedot"),
    VK_F24(135, "Dead Diaeresis"),
    VK_NAVIGATION_VIEW(136, "Dead Abovering"),
    VK_NAVIGATION_MENU(137, "Dead Doubleacute"),
    VK_NAVIGATION_UP(138, "Dead Caron"),
    VK_NAVIGATION_DOWN(139, "Dead Cedilla"),
    VK_NAVIGATION_LEFT(140, "Dead Ogonek"),
    VK_NAVIGATION_RIGHT(141, "Dead Iota"),
    VK_NAVIGATION_ACCEPT(142, "Dead Voiced Sound"),
    VK_NAVIGATION_CANCEL(143, "Dead Semivoiced Sound"),
    VK_NUMLOCK(144, "Num Lock"),
    VK_SCROLL(145, "Scroll"),
    VK_OEM_FJ_ROYA(150, "Ampersand"),
    VK_UNASSIGNED_97(151, "Asterisk"),
    VK_UNASSIGNED_98(152, "Double Quote"),
    VK_UNASSIGNED_99(153, "Less"),
    VK_UNASSIGNED_9A(154, "Print Screen"),
    VK_UNASSIGNED_9B(155, "Insert"),
    VK_UNASSIGNED_9C(156, "Help"),
    VK_UNASSIGNED_9D(157, "Meta"),
    VK_LSHIFT(160, "Left Shift"),
    VK_RSHIFT(161, "Right Shift"),
    VK_LCONTROL(162, "Left Ctrl"),
    VK_RCONTROL(163, "Right Ctrl"),
    VK_LMENU(164, "Left Menu"),
    VK_RMENU(165, "Right Menu"),
    VK_OEM_1(186, "Colon"),
    VK_OEM_PLUS(187, "Plus"),
    VK_OEM_COMMA(188, "Comma"),
    VK_OEM_MINUS(189, "Minus"),
    VK_OEM_PERIOD(190, "Period"),
    VK_OEM_2(191, "Slash"),
    VK_OEM_3(192, "Back Quote"),
    VK_OEM_4(219, "Open Bracket"),
    VK_OEM_5(220, "Back Slash"),
    VK_OEM_6(221, "Close Bracket"),
    VK_OEM_7(222, "Quote"),
    VK_RESERVED_E0(224, "Numpad Up"),
    VK_OEM_AX(225, "Numpad Down"),
    VK_OEM_102(226, "Numpad Left"),
    VK_ICO_HELP(227, "Numpad Right"),
    VK_OEM_ATTN(240, "Alphanumeric"),
    VK_OEM_FINISH(241, "Katakana"),
    VK_OEM_COPY(242, "Hiragana"),
    VK_OEM_AUTO(243, "Full Width"),
    VK_OEM_ENLW(244, "Half Width"),
    VK_OEM_BACKTAB(245, "Roman Characters"),
    ;
    final static Map<Integer, KeyCodeEnum> keyCode2Enum = new HashMap<>();
    final static Map<String, KeyCodeEnum> name2Enum = new HashMap<>();

    static {
        for (KeyCodeEnum value : KeyCodeEnum.values()) {
            keyCode2Enum.put(value.code, value);
            name2Enum.put(value.readableName, value);
        }
    }

    final int code;
    final String readableName;

    KeyCodeEnum(int code, String readableName) {
        this.code = code;
        this.readableName = readableName;
    }

    public static String getKeyNameByCode(int code) {
        return Optional.ofNullable(keyCode2Enum.get(code)).map(KeyCodeEnum::getReadableName).orElse(null);
    }

    public static KeyCodeEnum fromName(String readableName) {
        return name2Enum.get(readableName);
    }

    public static KeyCodeEnum fromCode(int code) {
        return keyCode2Enum.get(code);
    }

    public static String combineName(KeyCodeEnum... c1) {
        return Arrays.stream(c1)
                .filter(Objects::nonNull)
                .map(KeyCodeEnum::getReadableName)
                .collect(Collectors.joining(" + "));

    }

    public static KeyCodeEnum[] splitName(String combineName) {
        String[] strings = Optional.ofNullable(combineName).map(s -> s.split(" \\+ ")).orElse(null);
        if (strings == null || strings.length == 0) {
            return new KeyCodeEnum[0];
        }
        if (strings.length > 1) {
            KeyCodeEnum[] re = new KeyCodeEnum[2];
            re[0] = fromName(strings[0]);
            re[1] = fromName(strings[1]);
            return re;
        }
        KeyCodeEnum[] re = new KeyCodeEnum[1];
        re[0] = fromName(strings[0]);
        return re;
    }
}
